/*
 *    Copyright (c) 2014 Xiang Xu <xuxiang@mail.bnu.edu.cn>
 *
 *    Permission is hereby granted, free of charge, to any person
 *    obtaining a copy of this software and associated documentation
 *    files (the "Software"), to deal in the Software without
 *    restriction, including without limitation the rights to use,
 *    copy, modify, merge, publish, distribute, sublicense, and/or sell
 *    copies of the Software, and to permit persons to whom the
 *    Software is furnished to do so, subject to the following
 *    conditions:
 *
 *    The above copyright notice and this permission notice shall be
 *    included in all copies or substantial portions of the Software.
 *
 *    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *    OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef FACADE_MODEL_H
#define FACADE_MODEL_H

#include "split_action.h"
#include "facade_grammar.h"
#include "shape_symbol.h"
#include "facade_feature.h"

#include "rl_algorithm.h"

#include "opencv2/opencv.hpp"
#include "pcl/point_types.h"

#include <map>
#include <stack>

//! This is the agent in RL
/*!
 T his class is us*ed to parsing facade.
 */
class FacadeModel : public FacadeFeature, public RLAlgorithm
{
public:
    //! Constructor
    /*!
     \ param widthX F*acade width.
     \param widthY Facade Height.
     \param facade_grammar Facade grammar.
     */
    FacadeModel(int width, int height, boost::shared_ptr<FacadeGrammar> facade_grammar);

    //! Constructor
    /*!
     \ param res Faca*de resolution, stands for the meters of one pixel(grid).
     \param extMin The left-bottom corner of the facade.
     \param extRange The extent of the facade.
     \param facade_grammar Facade grammar.
     */
    FacadeModel(boost::shared_ptr<FacadeGrammar> facade_grammar);

    //! Initialize the model.
    /*!
     C alled in the c*onstructor.
     */
    void InitModel(int grouping);

    ~FacadeModel();

    //! Run the parsing algorithm.
    double RunParsingAlgorithm(int episodes, int greedy_episodes, double learning_rate);

    void RandomParsing();

    void RandomTask(boost::shared_ptr<ShapeSymbol>& state, int state_index);

    //! Calculate the symbol score.
    double CalculateScore(boost::shared_ptr<ShapeSymbol> shape_symbol);

    inline void SetSymbolWeights(std::vector<double> weights)
    {
        weights_ = weights;
    }

    //! Render the parsing result.
    void RenderResult(std::string& filename);

    void ConfigureOneDimensionFacade(std::string path);
    void ConfigureComplexOneDimensioFacade(std::string path);
    void ConfigureTwoDimensionFacade(std::string path);

    //! Print Q table to console.
    void PrintQTable();

    //! Save easy to read Q table to file.
    void SaveEasyReadQTable();

    void SaveLearningResult(std::string path, double score);
    // inline functions
    inline std::vector<boost::shared_ptr<ShapeSymbol> > get_split_result()
    {
        return split_result_;
    }
    inline int get_states_number()
    {
        return states_number_;
    }
    inline int get_actions_number()
    {
        return actions_number_;
    }

    //inline std::vector<int> get_suitable_actions(const int state) { return facade_grammar_->get_suitable_action(state); }
    inline std::vector<double> get_symbol_color(std::string symbol)
    {
        return facade_grammar_->get_symbol_color(symbol);
    }

    inline bool current_state_is_terminal()
    {
        return current_state_->is_terminal();
    }

    inline void set_action_parameter_file(std::string file)
    {
        action_parameter_file_ = file;
    }

protected:
    //! Reset the model.
    void Reset();

    //! Run a learning sub-task.
    double RunTask(boost::shared_ptr<ShapeSymbol>& state, int state_index);

    //! Initialize the state-index and index-state map.
    int InitStateMap();
    int InitGroupingStateMap();

    //! Initialize the action-index and index-action map.
    int InitActionMap();

    int InitActionMapFromFile();

    //! Initialize the index-suitable actions map.
    void InitSymbolSuitableActions();

private:
    int states_number_, actions_number_;		/*!< Number of state and action. */
    //	int state_ , next_state_, action_;
    int episodes_;								/*!< Number of episodes. */
    bool learning_, record_;					/*!< Whether to learning, record result. */
    double epsilon_, learning_rate_, gamma_;	/*!< learing parameters. */

    int state_grouping_;

    double last_average_, current_average_;

    std::map<SplitAction, int> action_to_index_;	/*!< action-index map. */
    std::map<int, SplitAction> index_to_action_;	/*!< index-action map. */
    std::map<Facadestate, int> state_to_index_;		/*!< state-index map. */
    std::map<int, Facadestate> index_to_state_;		/*!< index-state map. */

    std::map<int, int> state_action_map_;

    std::map<std::string, std::vector<int> > action_index_for_symbol_;

    boost::shared_ptr<ShapeSymbol> current_state_;	/*!< current state. */
    std::vector<boost::shared_ptr<ShapeSymbol> >  split_result_;	/*!< parsing result. */
    std::vector<int> result_is_exception_;

    std::string action_parameter_file_;
    std::vector<double> weights_;

    std::vector<std::string> grammar_result_;
};

#endif // FACADE_MODEL_H
